/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.ashmin.tritracker;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/*
 * This is the main entry point of the program
 *
 */
public class TriTracker extends MapActivity implements SensorEventListener,
        OnClickListener, LocationListener {
        private SensorManager sensorMgr;
	private Sensor sensorAccel;
	private TextView accuracyLabel;
	private TextView xLabel, yLabel, zLabel;
	private Button calibrateButton, startrecButton, stoprecButton;
        private MapView mapView;
        private MapController mapController;
        private LocationManager locationManager;
        private Location currentLocation;
        private MyLocationOverlay myLocationOverlay;
        private static final int ONE_MINUTE = 1000 * 60;


	private float[] a;

	private long lastUpdate = 0;
        private BufferedWriter outCSV;
        private boolean bSaveFile = Boolean.FALSE;

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.menu1, menu);
            return true;

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle item selection
            if (item.getItemId() == R.id.settings) {
                startActivity(new Intent(this, MyPreferences.class));
                return true;
            } else if (item.getItemId() == R.id.about) {
                return true;
            } else {

                return super.onOptionsItemSelected(item);
            }

        }


        public void runOnce() {
            try {
                //Creating a file to print the data into
                File root = Environment.getExternalStorageDirectory();

                if (root.canWrite()) {
                    File fileCSV = new File(root, "sensorData.csv");
                    FileWriter fwCSV = new FileWriter(fileCSV);
                    outCSV = new BufferedWriter(fwCSV);
                    bSaveFile = Boolean.TRUE;
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
            }
        }

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		accuracyLabel = (TextView) findViewById(R.id.accuracy_label);
		xLabel = (TextView) findViewById(R.id.x_label);
		yLabel = (TextView) findViewById(R.id.y_label);
		zLabel = (TextView) findViewById(R.id.z_label);
		calibrateButton = (Button) findViewById(R.id.calibrate_button);
		calibrateButton.setOnClickListener(this);
                startrecButton = (Button) findViewById(R.id.startrec_button);
                startrecButton.setOnClickListener(this);
                stoprecButton = (Button) findViewById(R.id.stoprec_button);
                stoprecButton.setOnClickListener(this);
                stoprecButton.setEnabled(Boolean.FALSE);
                mapView = (MapView) findViewById(R.id.mapview);

                //myPreferenceActivity = new MyPreferenceActivity();

	}

	@Override
	protected void onPause() {
		super.onPause();
		sensorMgr.unregisterListener(this, sensorAccel);
                locationManager.removeUpdates(this);
                myLocationOverlay.disableMyLocation();
		sensorMgr = null;
                if (bSaveFile == Boolean.TRUE) {
                    try {
                        outCSV.close();
                    } catch (IOException e) {

                    }

                }
	}

	@Override
	protected void onResume() {
		super.onResume();

		sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
		sensorAccel = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
		boolean accelSupported = sensorMgr.registerListener(this, sensorAccel,
				SensorManager.SENSOR_DELAY_FASTEST);
		if (!accelSupported) {
			// no accelerometer on this device
			sensorMgr.unregisterListener(this, sensorAccel);
			//accuracyLabel.setText(R.string.no_accelerometer);
		}
                bSaveFile = Boolean.FALSE;

                SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this);
                //
                mapView.setBuiltInZoomControls(true);
                myLocationOverlay = new MyLocationOverlay(this, mapView);
                mapView.getOverlays().add(myLocationOverlay);
                myLocationOverlay.enableCompass();
                myLocationOverlay.enableMyLocation();
                mapController = mapView.getController();
                mapController.setZoom(18);
                locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
                currentLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER, ONE_MINUTE, 50, this);

                //prefs.getInt("swimAccel", 1);
		    //Do something


	}

	public void onClick(View v) {
		if (v == calibrateButton) {
			// Clicked button
			//moved = 0;
			//speed = 0;
			//accelDiff = accel+accelDiff;
			//accel = 0;
                    //runOnce();

		}
                if (v == startrecButton) {
                    runOnce();
                    startrecButton.setEnabled(Boolean.FALSE);
                    stoprecButton.setEnabled(Boolean.TRUE);
                }
                if (v == stoprecButton) {
                    if (bSaveFile == Boolean.TRUE) {
                        try {
                            outCSV.close();
                            startrecButton.setEnabled(Boolean.TRUE);
                            stoprecButton.setEnabled(Boolean.FALSE);
                            bSaveFile = Boolean.FALSE;
                        } catch (IOException e) {

                        }
                    }
                }
	}

	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// this method is called very rarely, so we don't have to
		// limit our updates as we do in onSensorChanged(...)
		if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			switch (accuracy) {
			case SensorManager.SENSOR_STATUS_UNRELIABLE:
				//accuracyLabel.setText(R.string.accuracy_unreliable);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_LOW:
				//accuracyLabel.setText(R.string.accuracy_low);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
				//accuracyLabel.setText(R.string.accuracy_medium);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
				//accuracyLabel.setText(R.string.accuracy_high);
				break;
			}
		}
	}

	public void onSensorChanged(SensorEvent event) {
		int sensorType = event.sensor.getType();
		if (sensorType == Sensor.TYPE_ACCELEROMETER) {
			a = event.values;
                        /*
			long curTime = event.timestamp - lastUpdate;
			if (curTime > 1000000000) {
				lastUpdate = event.timestamp;

				//xLabel.setText(String.format("X:%+2.5f", a[0]));
				//yLabel.setText(String.format("Y:%+2.5f", a[1]));
				//zLabel.setText(String.format("Z:%+2.5f", a[2]));
				//build the string for the sd card
                                StringBuilder buff = new StringBuilder();
                                //buff.append(String.format("%+2.5f", (x+cx)));
                                buff.append(String.format("%d",lastUpdate));
                                buff.append(",");
                                buff.append(String.format("%+2.5f", a[0]));
                                buff.append(",");
                                buff.append(String.format("%+2.5f", a[1]));
                                buff.append(",");
                                buff.append(String.format("%+2.5f", a[2]));
                                //save it
                                if (bSaveFile == Boolean.TRUE) {
                                    try {
                                        outCSV.write(buff.toString());
                                        outCSV.newLine();
                                    } catch (IOException e) {
                                        // TODO Auto-generated catch block
                                    }
                                }
			}
                         *
                         */
		}
	}

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }


    @Override
    public void onLocationChanged(Location location) {
            int lat = (int) (location.getLatitude() * 1E6);
            int lng = (int) (location.getLongitude() * 1E6);
            double alt = location.getAltitude();
            float accuracy = location.getAccuracy();
            GeoPoint point = new GeoPoint(lat, lng);
            lastUpdate = location.getTime();
            mapController.animateTo(point);
            xLabel.setText(String.format("lat : %d", lat));
            yLabel.setText(String.format("long: %d", lng));
            zLabel.setText(String.format("alt :%+2.5f", alt));
            accuracyLabel.setText(String.format("acc :%+2.5f", accuracy));
            StringBuilder buff = new StringBuilder();
            //buff.append(String.format("%+2.5f", (x+cx)));
            buff.append(String.format("%d",lastUpdate));
            buff.append(",");
            buff.append(String.format("%d", lat));
            buff.append(",");
            buff.append(String.format("%d", lng));
            buff.append(",");
            buff.append(String.format("%+2.5f", alt));
            //save it
            if (bSaveFile == Boolean.TRUE) {
                try {
                    outCSV.write(buff.toString());
                    outCSV.newLine();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                }
            }


            //	mapController.setCenter(point);
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    /** Determines whether one Location reading is better than the current Location fix
      * @param location  The new Location that you want to evaluate
      * @param currentBestLocation  The current Location fix, to which you want to compare the new one
      */
    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > ONE_MINUTE;
        boolean isSignificantlyOlder = timeDelta < -ONE_MINUTE;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
        // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }

    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
          return provider2 == null;
        }
        return provider1.equals(provider2);
    }

}